package base_classes;
import grid.Couple;
import grid.Direction;
import grid.items.Body;

import java.awt.Point;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.net.ServerSocket;
import java.net.Socket;
import java.security.Provider;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Queue;
import java.util.Set;

import parameters.StaticParameters;

import connexion.IntegerMessage; 
import connexion.MASConnexion;
import connexion.Message;
import connexion.PerceptionMessage;
import connexion.StringMessage;


public class Server implements Runnable{
	public static final int portNumber = 2004;
	final static int UP=0;
	final static int DOWN=1;
	private static final int AGENT_NUMGER = 6;
	
	
	private static final int sleepTime = 10000;
	
	World w=new World(9, 9);
	
	ServerSocket providerSocket;
	

	MASConnexion[]masq=new MASConnexion[2];
	
	public void run()
	{
		try{
			providerSocket = new ServerSocket(portNumber, 10);
					
			getConnexions();
			
			sendNameMessage();
			sendWidth();
			sendHeight();
			sentAgentNumber();
			sendInitialPlacement();
			receiveInitialPlacement();
			sendStart();
			
			
			System.out.println(w);
			
			runServer();
			
		}
		catch(IOException ioException){
			ioException.printStackTrace();
		}
		finally{
			try{
				
				providerSocket.close();
			}
			catch(IOException ioException){
				ioException.printStackTrace();
			}
		}
	}

	private void sentAgentNumber() {
		sendAll(new IntegerMessage(IntegerMessage.AGENT_NUMBER, null, AGENT_NUMGER));
	}

	private void receiveInitialPlacement() {
		try {
			Thread.sleep(sleepTime);
		} catch (InterruptedException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		
		for(MASConnexion m:masq)
		{
			Queue<Message> queue=m.getMessages();
			for(Message msg:queue)
				w.handleMessage(msg);
		}

		sendAll(new StringMessage(StringMessage.PLACEMENT_FINISHED));
	}

	private void sendStart() {
		sendAll(new StringMessage(StringMessage.GAME_STARTED));
		if(StaticParameters.SERVER_CONNEXION_MESSAGES_VERBOSITY)
			System.out.println("server>game started sent");
	}
	private void sendInitialPlacement() {
		for(int i=0;i<masq.length;i++)
		{
			if(i==0)masq[i].sendMessage(new IntegerMessage(IntegerMessage.PLACEMENT_REASON,null, Direction.NORTH));
			if(i==1)masq[i].sendMessage(new IntegerMessage(IntegerMessage.PLACEMENT_REASON,null, Direction.SOUTH));
			if(i==2)masq[i].sendMessage(new IntegerMessage(IntegerMessage.PLACEMENT_REASON,null, Direction.EAST));
			if(i==3)masq[i].sendMessage(new IntegerMessage(IntegerMessage.PLACEMENT_REASON,null, Direction.WEST));
		}
		if(StaticParameters.SERVER_OUTGOING_MESSAGE_VERBOSITY)
			System.out.println("server>placement request sent");
		}

	private void sendHeight() {
		sendAll(new IntegerMessage(IntegerMessage.HEIGHT_REASON, null, w.gm.getDimensionY()));
	}

	private void sendWidth() {
		sendAll(new IntegerMessage(IntegerMessage.WIDTH_REASON, null, w.gm.getDimensionX()));
	}

	private void sendAll(Message m) {
		for(MASConnexion mc:masq)
			mc.sendMessage(m);
	}

	private void sendNameMessage() {
		for(int i=0;i<masq.length;i++)
		{
			masq[i].sendMessage(new StringMessage("team "+i,null,StringMessage.NAMING));
			masq[i].setTeam("team "+i);
		}
	}

	private void runServer() {
		while(w.getNumberOfRemainingTeams()>1)
		{
			try {
				Thread.sleep(sleepTime);
			} catch (InterruptedException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
			processMessages();
			if(StaticParameters.SERVER_CONNEXION_MESSAGES_VERBOSITY)
				System.out.println("moving phase");
			w.executeMoves();
			sendPositionsInformation(StringMessage.MOVE_PHASE_FINISHED);
			System.out.println(w);
			
			try {
				Thread.sleep(sleepTime);
			} catch (InterruptedException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
			processMessages();
			if(StaticParameters.SERVER_CONNEXION_MESSAGES_VERBOSITY)
			System.out.println("shooting phase");
			w.executeShots();
			sendPositionsInformation(StringMessage.SHOOT_PHASE_FINISHED);
			
			System.out.println(w);
		}
		if(w.getNumberOfRemainingTeams()>0)
		System.out.println("The winner is "+w.getWinningTeam());
	}

	private void sendPositionsInformation(String phase) {
		HashMap<Body,Map<Body,Point>>sensed=w.senseAll();
		
		for(Body b:sensed.keySet())
		{
			MASConnexion mas=getMASConnexion(b.getTeam());
			mas.sendMessage(new PerceptionMessage(b.getName(),w.getPosition(b),sensed.get(b)));
		}
			
			
sendAll(new StringMessage(phase));
	}

	private MASConnexion getMASConnexion(String team) {
		for(MASConnexion m:masq)
			if(m.getTeam().equals(team))
				return m;
		throw new Error();				
	}

	private void getConnexions() throws IOException {
		for(int i=0;i<masq.length;i++)
		{
			masq[i]=new MASConnexion(providerSocket.accept());
		}
		if(StaticParameters.SERVER_CONNEXION_MESSAGES_VERBOSITY)
			System.out.println("server> connected "+masq.length+" teams");

	}

	private void processMessages() {
		for(MASConnexion connection:masq)
		{
			Queue<Message> messages=connection.getMessages();
			for(Message m:messages)
				w.handleMessage(m);
		}
	}

	public static void main(String args[])
	{
		Server server = new Server();
			server.run();
	}

}
